<?php

namespace App\Http\Controllers;

use App\Models\ScoreInfo;
use App\Models\ScoreLog;
use App\Models\UserAccountBorrow;
use App\Models\UserAccountBorrowLog;
use App\Models\UserInfo;
use App\Models\UserLibraryInfo;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 积分规则模块
 * Class ScoreRule
 * @package app\common\controller
 */
class ScoreRuleController
{
    public $model = null;
    public $scoreLogModel = null;
    public function __construct()
    {
        $this->model = new ScoreInfo();
        $this->scoreLogModel = new ScoreLog();
    }

    /**
     * 积分规则
     */
    public function lists()
    {
        $res = $this->model->select('id', 'type_name', 'score', 'number', 'intro')->where('is_open', 1)->where('is_del', 1)->get()->toArray();

        $controllerObj = new Controller();
        if ($res) {
            return $controllerObj->returnApi(200, '获取成功', true, $res);
        }
        return $controllerObj->returnApi(202, '获取失败');
    }

    /**
     * 获取用户当前积分
     */
    public function getUserScore($user_id, $account_id = null)
    {
        $score_table = config('other.score_table');
        //优先使用读者证号
        if ($account_id && $score_table == 'user_account_lib') {
            $score = UserLibraryInfo::where('id', $account_id)->value('score');
            if (empty($score) && ($score !== 0 && $score !== '0')) {
                return '积分获取失败';
            }
            return (int)$score;
        }
        if (empty($user_id)) {
            return '积分获取失败';
        }

        $res = UserInfo::select('account_id', 'id', 'score')->where('id', $user_id)->first();
        if (empty($res)) {
            return '积分获取失败';
        }
        if ($score_table == 'user_info') {
            return (int)$res->score;
        }

        if (empty($res->account_id)) {
            return '未绑定读者证，请先绑定';
        }

        $score = UserLibraryInfo::where('id', $res->account_id)->value('score');
        if (empty($score) && ($score !== 0 && $score !== '0')) {
            return '积分获取失败';
        }
        return (int)$score;
    }

    /**
     * 设置用户当前积分
     */
    public function setUserScore($user_id, $account_id = null, $change_score = 0)
    {
        $score_table = config('other.score_table');
        //优先使用读者证号
        if ($account_id && $score_table == 'user_account_lib') {
            $account_info = UserLibraryInfo::where('id', $account_id)->first();
            if (empty($account_info)) {
                return '积分获取失败';
            }
            $score = $account_info->score + $change_score;

            if ($score < 0) {
                $change_score = $account_info->score; //原本积分就是扣除积分
                $change_score = -$change_score;
                $account_info->score = 0; //积分不能为负数
            } else {
                $account_info->score = $score;
            }
            $account_info->save();
            return $change_score; //返回本次扣除积分
        }

        if (empty($user_id)) {
            return '积分获取失败';
        }

        $res = UserInfo::select('account_id', 'id', 'score')->where('id', $user_id)->first();
        if (empty($res)) {
            return '积分获取失败';
        }
        if ($score_table == 'user_info') {
            return (int)$res->score;
        }

        if (empty($res->account_id)) {
            return '未绑定读者证，请先绑定';
        }

        $account_info = UserLibraryInfo::where('id', $account_id)->first();
        if (empty($account_info)) {
            return '积分获取失败';
        }

        $score = $account_info + $change_score;
        if ($score < 0) {
            $change_score = $account_info->score; //原本积分就是扣除积分
            $change_score = -$change_score;
            $account_info->score = 0; //积分不能为负数
        } else {
            $account_info->score = $score;
        }
        $account_info->save();
        return $change_score; //返回本次扣除积分
    }


    /**
     * 根据类型获取积分
     * @parma type
     */
    public function getScoreByType($type)
    {
        if (config('other.is_need_score')) {
            return $this->model->where('type', $type)->where('score', '<>', 0)->where('is_open', 1)->where('is_del', 1)->first();
        }
        return false; //如果不需要直接返回
    }



    /**
     * 判断积分状态，是否够操作
     */
    public function checkScoreStatus($type, $user_id = null, $account_id = null)
    {
        $score_info = $this->getScoreByType($type);

        if (!$score_info) {
            return ['code' => 201, 'msg' => '无效积分规则']; //没有规格，不操作
        }

        //不操作积分
        if (empty($score_info->score)) {
            return ['code' => 201, 'msg' => '无须操作积分']; //正常，不操作积分
        }

        $user_score = $this->getUserScore($user_id, $account_id);

        if (is_string($user_score)) {
            return ['code' => 202, 'msg' => $user_score]; //用户积分获取失败，报错
        }

        /**检查次数限制  注册和绑定不受限，都只能一次*/
        if ($score_info->number > 0 && !in_array($type, [1])) {
            $date = date("Y-m-d");
            $score_list = $this->scoreLogModel->where('account_id', $account_id)->where('type_id', $type)->where(function ($query) use ($date) {
                $query->whereRaw(DB::raw("DATE_FORMAT(`create_time`,'%Y-%m-%d') = '$date'"));
            })->pluck('score');
            $count = 0; //计算每天有效次数
            foreach ($score_list as $key => $val) {
                if ($score_info->score > 0) {
                    $count = $val > 0 ? $count + 1 : $count - 1;
                } else {
                    $count = $val > 0 ? $count - 1 : $count + 1;
                }
            }

            if ($count >= $score_info->number) {
                return ['code' => 201, 'msg' => '今天积分操作次数已满']; //正常，不操作积分
            }
        }
        $new_user_score =  $user_score + $score_info->score;

        if (!empty($new_user_score) && $new_user_score < 0) {
            return ['code' => 203, 'msg' => '积分不足，操作失败', 'user_score' => $user_score, 'score_info' => $score_info->toArray()]; //错误
        }

        return ['code' => 200, 'msg' => '', 'user_score' => $user_score, 'score_info' => $score_info->toArray()]; //正常，要操作积分
    }


    /**
     * 操作(修改)积分 除商品外
     */
    public function scoreChange($score_info, $user_id = null, $account_id = null, $system_id = 0, $time = null)
    {
        $user_score = $this->getUserScore($user_id, $account_id);

        if (is_string($user_score)) {
            return ['code' => 202, 'msg' => $user_score];
        }

        //修改用户积分
        $change_score = $this->setUserScore($user_id, $account_id, $score_info['score_info']['score']);
        /**记录积分log */
        $log_data = [
            'user_id' => $user_id,
            'account_id' => $account_id,
            'system_id' => $system_id,
            'score' => $change_score,
            'total_score' => $score_info['score_info']['score'],
            'type_id' => $score_info['score_info']['id'],
            'type' => $score_info['score_info']['type_name'],
            'intro' => $score_info['score_info']['intro'],
            'create_time' => $time ? $time : date("Y-m-d H:i:s")
        ];
        $this->addScoreLog($log_data);

        return ['code' => 200, 'msg' => '积分操作成功'];
    }

    /**
     * 积分退还 除商品外
     * @param $score 原本的积分  如果是减，这里就是正数，加就是负数
     */
    public function scoreReturn($type, $score, $user_id = null, $account_id = null, $intro = null, $system_id = 0, $title = '')
    {
        $score *= -1; //改变积分符号

        $score_table = config('other.score_table');
        //直接修改用户积分
        if ($score_table == 'user_account_lib') {
            $res = UserLibraryInfo::where('id', $account_id)->first();
        } else {
            $res = UserInfo::select('account_id', 'id', 'score')->where('id', $user_id)->first();
        }

        $res->score = $res->score + $score;
        $res->save();

        //获取积分规则
        $score_rule = $this->getScoreByType($type);
        /**记录积分log */
        $log_data = [
            'user_id' => $user_id,
            'account_id' => $account_id,
            'system_id' => $system_id,
            'score' => $score,
            'total_score' => $score,
            'type_id' => !empty($score_rule['id']) ? $score_rule['id'] : 0,
            'type' => !empty($title) ? $title : $score_rule['type_name'],
            'intro' => !empty($intro) ? $intro : '积分回退',
            'create_time' => date("Y-m-d H:i:s")
        ];

        $this->addScoreLog($log_data);

        return true;
    }

    /**
     * 商品、欠款缴纳积分扣除
     * @param $score 积分 如果是减，这里就是正数，加就是负数
     * @param $type_id 类型id  0 为商品   999 为缴纳欠款
     */
    public function scoreGoodChange($score, $user_id = null, $account_id = null, $type = null,  $type_id = 0, $system_id = 0, $msg = null)
    {
        $score *= -1; //改变积分符号

        $user_score = $this->getUserScore($user_id, $account_id);

        if (is_string($user_score)) {
            return ['code' => 202, 'msg' => $user_score];
        }

        if ($user_score + $score < 0) {
            return ['code' => 202, 'msg' => '积分不足，不允许兑换'];
        };

        //修改用户积分
        $change_score = $this->setUserScore($user_id, $account_id, $score);

        /**记录积分log */
        $log_data = [
            'user_id' => $user_id,
            'account_id' => $account_id,
            'system_id' => $system_id,
            'score' => $change_score,
            'total_score' => $score,
            'type_id' => $type_id,
            'type' => $type,
            'intro' => $msg,
            'create_time' => date("Y-m-d H:i:s")
        ];

        $this->addScoreLog($log_data);
    }

    /**
     * 商品积分返还
     * @param $score 原本的积分 不管正负
     */
    public function scoreGoodReturn($score, $user_id, $account_id, $type, $msg, $system_id)
    {
        $score_table = config('other.score_table');
        //直接修改用户积分
        if ($score_table == 'user_account_lib') {
            $res = UserLibraryInfo::where('id', $account_id)->first();
        } else {
            $res = UserInfo::select('account_id', 'id', 'score')->where('id', $user_id)->first();
        }
        $res->score = $res->score + $score;
        $res->save();

        /**记录积分log */
        $log_data = [
            'user_id' => $user_id,
            'account_id' => $account_id,
            'system_id' => $system_id,
            'score' => $score,
            'total_score' => $score,
            'type_id' => 0,
            'type' => $type,
            'intro' => $msg,
            'create_time' => date("Y-m-d H:i:s")
        ];

        $this->addScoreLog($log_data);
    }


    /**
     * 积分字样
     */
    public function getScoreMsg($score)
    {
        return $score > 0 ? '退回' : "返还";
    }


    /**
     * 添加积分信息
     * @parma $data
     */
    public function addScoreLog($data)
    {
        $scoreLogModel = new ScoreLog(); //重新初始化对象，避免多次调用，只成功一次
        $scoreLogModel->user_id = !empty($data['user_id']) ? $data['user_id'] : 0;
        $scoreLogModel->account_id = $data['account_id'];
        $scoreLogModel->system_id = !empty($data['system_id']) ? $data['system_id'] : 0; //系统消息id
        $scoreLogModel->score = $data['score'];
        $scoreLogModel->total_score = $data['total_score'];
        $scoreLogModel->type_id = $data['type_id'];
        $scoreLogModel->type = $data['type'];
        $scoreLogModel->intro = $data['intro'];
        $scoreLogModel->manage_id = !empty(request()->manage_id) ? request()->manage_id : 0;
        $scoreLogModel->create_time = !empty($data['create_time']) ? $data['create_time'] : date('Y-m-d H:i:s');

        $scoreLogModel->save();
    }


    /**
     * 获取用户积分信息，增加用户积分和扣除积分
     */
    public function getBorrowInfo($user_id, $account_id)
    {
        //判断积分系统是否开启
        if (!config('other.is_need_score')) {
            return false; //未设置积分规则
        }
        $score = ScoreInfo::whereIn('type', [8, 9, 10, 25])->where('is_open', 1)->where('is_del', 1)->first();
        if (empty($score)) {
            return false; //未设置积分规则
        }
        //查询之前对接的查询时间，按时间去查询数据
        $userAccountBorrowLogModel = new UserAccountBorrowLog();
        $create_time = $userAccountBorrowLogModel->where('account_id', $account_id)->where('logtype', 30001)->orderBy('create_time', 'desc')->value('create_time');
        if ($create_time) {
            $start_time = date('Y-m-d', strtotime($create_time) - 3 * 24 * 60 * 60); //多查询3天的数据
        } else {
            $start_time = "2025-01-01"; //开始时间
        }
        $end_time = date('Y-m-d'); //结束时间
        $this->getBorrowScore($user_id, $account_id, $start_time, $end_time, 30001);

        $create_time = $userAccountBorrowLogModel->where('account_id', $account_id)->where('logtype', 30002)->orderBy('create_time', 'desc')->value('create_time');
        if ($create_time) {
            $start_time = date('Y-m-d', strtotime($create_time) - 3 * 24 * 60 * 60); //多查询3天的数据
        } else {
            $start_time = "2025-01-01"; //开始时间
        }
        $this->getBorrowScore($user_id, $account_id, $start_time, $end_time, 30002);
    }

    /**
     * 根据具体借还数据，增减积分
     * logtype 30001 借 30002 还
     */
    public function getBorrowScore($user_id, $account_id, $start_time, $end_time, $logtype)
    {
        // $account_info = $this->getUserScore(null, $account_id);
        $account = UserLibraryInfo::where('id', $account_id)->value('account');
        $controllerObj = new Controller();
        $libApi = $controllerObj->getLibApiObj();
        $getLastBorrowInfo = $libApi->getReturnData($account, 1, 100, $start_time, $end_time, null, $logtype, true);
        if ($getLastBorrowInfo['success'] !== true || empty($getLastBorrowInfo['hloanlist']) || empty($getLastBorrowInfo['total'])) {
            return false; //代表无数据
        }

        DB::beginTransaction();
        try {
            $userAccountBorrowLogModel = new UserAccountBorrowLog();
            //已经计算过的id
            $use_api_id = $userAccountBorrowLogModel->where('rdid', $account)->pluck('api_id')->toArray();

            foreach ($getLastBorrowInfo['hloanlist'] as $key => $val) {
                //判断此记录是否已经使用
                if (in_array($val['id'], $use_api_id)) {
                    continue;
                }

                //数据添加到数据表
                $userAccountBorrowLogModel->insert([
                    'api_id' => $val['id'],
                    'user_id' => $user_id, //记录当前读者证的请求时间
                    'account_id' => $account_id, //记录当前读者证的请求时间
                    'loantime' => $val['loantime'],
                    'rownum_' => $val['rownum_'],
                    'optime' => $val['optime'],
                    'author' => $val['author'] ?? '',
                    'callno' => $val['callno'],
                    'opuser' => $val['opuser'],
                    'isbn' => $val['isbn'],
                    'title' => $val['title'],
                    'logtype' => $val['logtype'],
                    'oplocalname' => $val['oplocalname'],
                    'rdid' => $val['rdid'],
                    'bookrecno' => $val['bookrecno'],
                    'barcode' => $val['barcode'],
                    'returntime' => $val['returntime'],
                    'create_time' => date('Y-m-d H:i:s')
                ]);

                $score_info = $this->getScoreInfo($val);
                if (empty($score_info)) {
                    continue; //不进行任何处理
                }
                $score_info['score_info'] = $score_info->toArray(); //统一数据格式
                //积分不够，直接减为负数
                // $score_status = $this->checkScoreStatus($score_info['type'], $account_id, true);
                // if ($score_status['code'] !== 200) {
                //     return false; //不进行任何处理
                // }


                $change_time = $val['optime'];
                $system_id = $controllerObj->systemAdd($score_info['score_info']['type_name'], $user_id, $account_id, 50, 0, $score_info['score_info']['intro'] . " ，书名为：《" . $val['title'] . '》', $change_time);
                $selfObj = new self();
                $selfObj->scoreChange($score_info, $user_id, $account_id, $system_id, $change_time); //添加积分消息

                /*//只返回已归还的记录
                if($val['eventType'] === 'Eg' || $val['eventType'] === 'Ec' || $val['eventType'] === 'Ed' || $val['eventType'] === 'Ef') {

                "hloanlist": [
                    {
                        "loantime": "2025-04-03 10:10:39",
                        "rownum_": 1,
                        "optime": "2025-04-03 10:11:00",
                        "author": "刘岩编",
                        "callno": "I242.4/95",
                        "opuser": "YBWJ",
                        "isbn": "978-7-5355-7697-2",
                        "title": "西游记",
                        "logtype": "30002",
                        "oplocalname": "oto网借书库",
                        "rdid": "51150110004020",
                        "id": "103495090",
                        "bookrecno": 1350459,
                        "barcode": "51150010100354195",
                        "returntime": "2025-05-03 10:10:39"
                    },
                }*/
            }

            DB::commit();
            return true;
        } catch (\Exception $e) {
            Log::error('积分操作异常');
            Log::error($e->getMessage() . $e->getFile() . $e->getLine());

            DB::rollBack();
            return false;
        }
    }

    /**
     * 获取对应积分
     */
    public function getScoreInfo($data)
    {
        //30001 借，30002 还
        if ($data['logtype'] == 30001) {
            $type = 8; //借阅1次一分
        } elseif ($data['logtype'] == 30002) {
            if ($data['optime'] <= $data['returntime']) {
                // $type = 9;
                return false; //按时还，不操作积分  returntime 应归还时间 optime 实际还书时间
            } else {
                // $type = 10;
                $day = time_diff_day($data['returntime'], $data['optime']);
                if ($day <= 10) {
                    $type = 10; //预期10天内还回书籍减少 1 积分（每日限制100次）
                } else {
                    $type = 25; //预期10天以上还回书籍减少 2 积分（每日限制100次）
                }
            }
        } else {
            return false;
        }

        $score = ScoreInfo::where('type', $type)->where('is_open', 1)->where('is_del', 1)->first();
        return $score;
    }
}
